package com.blockmeta.bbs.businesslibrary.websocket;

import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;

import com.blankj.utilcode.util.LogUtils;
import com.blockmeta.bbs.businesslibrary.iosocket.client.IO;
import com.blockmeta.bbs.businesslibrary.iosocket.client.Socket;

import java.net.URISyntaxException;

import io.socket.emitter.Emitter;
import io.socket.engineio.client.transports.WebSocket;
import okio.ByteString;


public class SocketIOManager implements ISocketIOManager {

  public static final String SOCKET_RESPONSE = "socket_response";
  private String wsUrl;
  private Socket mSocket;
  private int mCurrentStatus = WsStatus.DISCONNECTED;     //websocket连接状态
  private SocketIOStatusListener socketStatusListener;
  protected int 	 m_nSession;
  protected final static String[] Urls = {"9998","9997"};

  public SocketIOManager(Builder builder) {
    wsUrl = builder.wsUrl;
    m_nSession = builder.session;
  }

  private void initWebSocket() {
    try {
      IO.Options opts = new IO.Options();
      //采用自己的重连机制
      opts.reconnection = true;
      opts.multiplex = false;
//      opts.path = "/socket.io";
//      opts.hostname = wsUrl;
//      opts.forceNew = true;
      opts.transports = new String[]{WebSocket.NAME};
//      mSocket = IO.socket("http://47.99.54.36:9998",opts);
//      mSocket = IO.socket("http://192.168.168.176:9995",opts);
//      mSocket = IO.socket("http://socket.blockmeta.com/",opts);
      mSocket = IO.socket(wsUrl,opts);
    } catch (URISyntaxException e) {
      throw new RuntimeException(e);
    }
    mSocket.on(Socket.EVENT_CONNECT,onConnect);
    mSocket.on(Socket.EVENT_DISCONNECT,onDisconnect);
    mSocket.on(Socket.EVENT_CONNECT_ERROR, onConnectError);
    mSocket.on(Socket.EVENT_CONNECT_TIMEOUT, onConnectError);
    mSocket.on(SOCKET_RESPONSE, onNewMessage);
    mSocket.connect();

  }

  @Override
  public Socket getSocket() {
    return mSocket;
  }


  public void setSocketIOStatusListener(SocketIOStatusListener wsStatusListener) {
    this.socketStatusListener = wsStatusListener;
  }

  @Override
  public synchronized boolean isConnected() {
    return mCurrentStatus == WsStatus.CONNECTED;
  }

  @Override
  public synchronized int getCurrentStatus() {
    return mCurrentStatus;
  }

  @Override
  public synchronized void setCurrentStatus(int currentStatus) {
    this.mCurrentStatus = currentStatus;
  }

  @Override
  public void startConnect() {
    buildConnect();
  }

  @Override
  public void stopConnect() {
    disconnect();
  }




  private void disconnect() {
    if (mCurrentStatus == WsStatus.DISCONNECTED) {
      return;
    }
    mSocket.disconnect();

    mSocket.off(Socket.EVENT_CONNECT, onConnect);
    mSocket.off(Socket.EVENT_DISCONNECT, onDisconnect);
    mSocket.off(Socket.EVENT_CONNECT_ERROR, onConnectError);
    mSocket.off(Socket.EVENT_CONNECT_TIMEOUT, onConnectError);
    mSocket.off(SOCKET_RESPONSE, onNewMessage);
    setCurrentStatus(WsStatus.DISCONNECTED);
  }

  private synchronized void buildConnect() {
    switch (getCurrentStatus()) {
      case WsStatus.CONNECTED:
      case WsStatus.CONNECTING:
        break;
      default:
        setCurrentStatus(WsStatus.CONNECTING);
        initWebSocket();
    }
  }

  //发送消息
  @Override
  public boolean sendMessage(String event, String msg) {
    return send(event, msg);
  }

  @Override
  public boolean sendMessage(String event, Object msg) {
    return send(event, msg);
  }

  @Override
  public boolean sendMessage(String event, ByteString byteString) {
    return send(event, byteString);
  }

  private boolean send(String event, Object msg) {
    boolean isSend = true;
    if (mSocket != null && mCurrentStatus == WsStatus.CONNECTED) {
      mSocket.emit(event, msg);
    }
    return isSend;
  }

  public boolean sendMessage(String event) {
    boolean isSend = true;
    if (mSocket != null && mCurrentStatus == WsStatus.CONNECTED) {
      mSocket.emit(event);
    }
    return isSend;
  }

  //检查网络是否连接
  private boolean isNetworkConnected(Context context) {
    if (context != null) {
      ConnectivityManager mConnectivityManager = (ConnectivityManager) context
          .getSystemService(Context.CONNECTIVITY_SERVICE);
      NetworkInfo mNetworkInfo = mConnectivityManager
          .getActiveNetworkInfo();
      if (mNetworkInfo != null) {
        return mNetworkInfo.isAvailable();
      }
    }
    return false;
  }

  public int getSession() {
    return m_nSession;
  }

  private Emitter.Listener onConnect = new Emitter.Listener() {
    @Override
    public void call(Object... args) {
      setCurrentStatus(WsStatus.CONNECTED);
      if (socketStatusListener != null) {
        for (Object o :
                args) {
          LogUtils.d("author"+ "onConnect"+o.toString());
        }
        socketStatusListener.onOpen(getArgsContent(args));
      }
    }
  };

  private Object getArgsContent(Object[] args) {
    return args.length > 1 ? args[1] : args.length == 1 ? args[0] : args.toString();
  }

  private Emitter.Listener onDisconnect = new Emitter.Listener() {
    @Override
    public void call(Object... args) {
      if (socketStatusListener != null) {
        for (Object o :
                args) {
          LogUtils.d("author"+ "onDisconnect"+o.toString());
        }
        socketStatusListener.onClosed(getArgsContent(args));
      }
      setCurrentStatus(WsStatus.DISCONNECTED);
    }
  };

  private Emitter.Listener onConnectError = new Emitter.Listener() {
    @Override
    public void call(Object... args) {
      if (socketStatusListener != null) {
        for (Object o :
                args) {
          LogUtils.d("author"+ "onConnectError"+ o.toString());
        }
        socketStatusListener.onFailure(getArgsContent(args));
        setCurrentStatus(WsStatus.FAIL);
      }
    }
  };

  private Emitter.Listener onNewMessage = new Emitter.Listener() {
    @Override
    public void call(final Object... args) {
      if (socketStatusListener != null) {
        for (Object o :
                args) {
          LogUtils.d("author"+ "onNewMessage"+ o.getClass());
          if(o.getClass().equals(String.class))
          {
            LogUtils.d("author"+ "onNewMessage"+ o.toString());
          }
        }
        socketStatusListener.onMessage(getArgsContent(args));
      }
    }
  };

  public static final class Builder {

    private String wsUrl;
    private int session;


    public Builder wsUrl(String val) {
      wsUrl = val;
      return this;
    }

    public Builder socketSession(int val) {
      session = val;
      return this;
    }

    public SocketIOManager build() {
      return new SocketIOManager(this);
    }
  }
}
